/*
 * Functions to interract with host
 */
#pragma once

// File with virtiofs-requests definitions
#ifndef offsetof
#define offsetof FIELD_OFFSET
#endif
#include "../../viofs/shared/fuse.h"
#include "fusecache.h"

// Some of the constants defined in Windows doesn't match the values that are
// used in Linux. Don't try to understand, just redefine them to match.
#undef O_DIRECTORY
#undef O_EXCL
#undef S_IFMT
#undef S_IFDIR
#undef S_IFREG
#undef S_IFLNK

#define O_DIRECTORY 0200000
#define O_EXCL      0200

#define S_IFMT      0170000
#define S_IFSOCK    0140000
#define S_IFDIR      040000
#define S_IFREG     0100000
#define S_IFLNK     0120000

#undef O_RDONLY
#undef O_WRONLY
#undef O_RDWR
#undef O_APPEND

#define O_RDONLY    0x0000  // open for reading only
#define O_WRONLY    0x0001  // open for writing only
#define O_RDWR      0x0002  // open for reading and writing
#define O_TRUNC     0x0200  // truncate file to zero
#define O_APPEND    0x0400  // writes done at eof


// Definitions of linux-host errors
#define LIN_EPERM   1
#define LIN_ENOENT  2
#define LIN_EIO     5
#define LIN_EBADF   9
#define LIN_ENOMEM  12
#define LIN_EACCES  13
#define LIN_EEXIST  17
#define LIN_ENODEV  19
#define LIN_EINVAL  22
#define LIN_ETXTBSY 26
#define LIN_ENAMETOOLONG 36
#define LIN_ENOSYS  38
#define LIN_EOPNOTSUPP 95

#define LIN_STATFS_BLOCK_SIZE 512

#define UNIX_ACCESS_MODE_MASK  07777
#define UNIX_ACCESS_MODE_WRITE 0222

#define UNIX_ACCESS_MODE_RWRR       0644
#define UNIX_ACCESS_MODE_RWRWR      0664
#define UNIX_ACCESS_MODE_DIR        040111
#define UNIX_ACCESS_MODE_DIR_XXX    0111


NTSTATUS
FuseForgetRequest(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  UINT32                  ShareId,
    IN  UINT64                  FuseNodeId,
    IN  UINT64                  NLookup);


UINT64
UnixTimeToWindows(
    UINT64  time,
    UINT32  nsec);

// Converts posix file attributes to Windows
// Name can be full-file-path or just file name
// namelen - length of name withouth '\0'
ULONG
PosixAttr2FileAttr(
    IN  const struct fuse_attr* attr,
    IN  const CHAR* name,
    IN  int namelen);

NTSTATUS
HostAccessInit(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt);

VOID
HostAccessDeinit(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt);

VOID
HostInitShareStruct(
    PHWFS_SHARE                 pShare);

NTSTATUS
HostConnectShare(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PUNICODE_STRING         pFolderName,
    OUT PHWFS_SHARE             pShare);

BOOLEAN
HostReconnectShare(
    PHWFS_DEVICE_EXTENSION  pDevExt,
    PHWFS_SHARE             pShare,
    UINT64                  ShareGeneration);

BOOLEAN
HostShareIsConnected(
    IN  PHWFS_SHARE             pShare);

VOID
HostShareSetConnected(
    IN  PHWFS_SHARE             pShare,
    IN  BOOLEAN                 isConnected);

NTSTATUS HostDisconnectShare(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_SHARE             pShare);

// ForcedUpdate - updateVolInfo even if last update
// was less then 100ms ago.
NTSTATUS HostUpdateVolumeInfo(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_SHARE             pShare,
    IN  BOOLEAN                 ForcedUpdate);

NTSTATUS HostCreateFile(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_SHARE             pShare,
    IN  PUNICODE_STRING         pFileName,
    IN  PNT_CREATE_PARAMETERS   pNtCreateParams,
    OUT PHWFS_FILE              pHwfsFile,
    OUT PULONG                  pCreateAction,
    OUT PHWFS_FILE_INFO         pFileInfo);

NTSTATUS HostCloseFile(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_SHARE             pShare,
    IN  PHWFS_FILE              pHwfsFile);

NTSTATUS HostLookupEntry(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_SHARE             pShare,
    IN  UINT64                  DirNodeId,
    IN  PCHAR                   pUtf8FileName,
    OUT struct fuse_entry_out* pFuseEntry);

/*
 * Returns buffer with fuse_direntplus entries.
 * The parameter uOffset is opaque. Should be taken from direntplus.
 * return STATUS_SUCCESS if directory is read.
 *        STATUS_BUFFER_OVERFLOW if there are more data to read.
 */
NTSTATUS HostReadDirectory(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_FILE              pHwfsFile,
    IN  UINT64                  uOffset,
    IN  PVOID                   pBuffer,
    IN  ULONG                   BufSize,
    OUT PUINT64                 pBytesTransferred);

NTSTATUS HostReadFile(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_FILE              pHwfsFile,
    IN  UINT64                  uOffset,
    IN  PMDL                    pMdlBuffer,
    IN  UINT64                  Size,
    OUT PUINT64                 pBytesTransferred);

NTSTATUS HostSetBasicFileAttributes(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_FILE              pHwfsFile,
    IN  UINT32                  FileAttributes,
    IN  INT64                   AccessTime,
    IN  INT64                   WriteTime,
    IN  INT64                   ChangeTime,
    OUT PHWFS_FILE_INFO         pFileInfo);

NTSTATUS HostWriteFile(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_FILE              pHwfsFile,
    IN  UINT64                  uOffset,
    IN  PMDL                    pMdlBuffer,
    IN  UINT64                  Size,
    OUT PUINT64                 pBytesTransferred);

NTSTATUS HostRenameFile(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_SHARE             pShare,
    IN  PHWFS_FILE              pHwfsFile,
    IN  PUNICODE_STRING         pNewFileName,
    IN  BOOLEAN                 ReplaceIfExists);

NTSTATUS
HwFsUpdateFileInfo(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_FILE              pHwfsFile,
    OUT PHWFS_FILE_INFO         pFileInfo);

NTSTATUS
HwFsSetAllocSize(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_FILE              pHwfsFile,
    IN  UINT64                  NewSize,
    OUT PHWFS_FILE_INFO         pFileInfo);

NTSTATUS
HwFsSetFileSize(
    IN  PHWFS_DEVICE_EXTENSION  pDevExt,
    IN  PHWFS_FILE              pHwfsFile,
    IN  UINT64                  NewSize,
    OUT PHWFS_FILE_INFO         pFileInfo);
